#ifndef UUID_2F52BABF89DD48F7A2BC538DF70E2DD4
#define UUID_2F52BABF89DD48F7A2BC538DF70E2DD4

#include <gvl/support/cstdint.hpp>
#include <gvl/system/memory.hpp>
#include <vector>

int const channelCount = 16;

namespace gvl { struct octet_stream_reader; }

struct Sound
{
	Sound(gvl::octet_stream_reader&);

	std::vector<int16_t> data;
};

struct Channel
{
	enum
	{
		Looping = (1<<0)
	};

	Channel()
	: sound(0)
	{
	}

	// Mutator read/write
	uint32_t id;

	// Mutator write once, mixer read
	uint32_t flags;

	// Mutator write once, mixer read
	Sound* sound;

	// Mutator write once, mixer read/write
	//uint32_t pos;
	double start;

	double soundpos;
	double stride;
	uint32_t volumes;
};

typedef void PaStream;

struct Mixer
{
	Mixer();
	~Mixer();

	uint32_t add(Sound* sound);

	void swap(uint32_t idx1, uint32_t idx2)
	{
		uint32_t temp = channels[idx1];
		channels[idx1] = channels[idx2];
		channels[idx2] = temp;
	}

	uint32_t activeChannels() const
	{
		GVL_READ_SYNC();
		return (writePos - tailPos) & (channelCount-1);
	}

	uint32_t freeChannels() const
	{
		return channelCount - activeChannels();
	}

	int checkHandle(uint32_t h)
	{
		return (channelStates[h & 0xffff].id == h) ? (h & 0xffff) : -1;
	}

	void setSpeed(uint32_t h, double speed)
	{
		int ch = checkHandle(h);
		if(ch < 0) return;

		channelStates[ch].stride = speed;
	}

	void setVolumes(uint32_t h, uint32_t volumes)
	{
		int ch = checkHandle(h);
		if(ch < 0) return;

		channelStates[ch].volumes = volumes;
	}

	void setFlags(uint32_t h, uint32_t flags)
	{
		int ch = checkHandle(h);
		if(ch < 0) return;

		channelStates[ch].flags = flags;
	}

	bool addChannel(int16_t* out, unsigned long frameCount, double now, Channel& ch);
	void mix(void *output, unsigned long frameCount, double now);
	void start();

	uint32_t nextId;
	Channel channelStates[channelCount];

	uint32_t writePos, tailPos;
	uint32_t channels[channelCount];

	PaStream* str;
	int32_t baseFrame;
	bool initialized;
	double outputLatency;
	double sampleRate;
};

extern Mixer mixer;

#endif // UUID_2F52BABF89DD48F7A2BC538DF70E2DD4
